Initializing Random Choice¶

In [1]:
from random import choices
In [2]:
%matplotlib inline
import numpy as np
import networkx as nx
import pandas as pd
import altair as alt
import nx_altair as nxa

Eric Pastore¶

Dr. Ladd¶

CIS 397¶

April 25, 2024¶

Homework 10: Epidemics in Social Networks¶

1. Analyzing the Epidemic Network¶

In [3]:
p = 0.625 # Calculate the probability for a node to become infected
In [4]:
G = nx.read_weighted_edgelist("contact-high-school-proj-graph.txt")
print(G)
Graph with 327 nodes and 5818 edges
In [5]:
nx.degree(G) # Calculate the degree values for each node in the network
Out[5]:
DegreeView({'1': 26, '2': 29, '3': 23, '4': 36, '5': 43, '6': 34, '7': 28, '8': 33, '9': 69, '10': 27, '11': 62, '12': 38, '13': 48, '14': 20, '15': 26, '16': 30, '17': 67, '18': 61, '19': 22, '20': 39, '21': 39, '22': 51, '23': 29, '24': 24, '25': 37, '26': 29, '27': 41, '28': 41, '29': 36, '31': 38, '30': 34, '32': 45, '33': 32, '35': 35, '34': 15, '36': 59, '37': 49, '38': 47, '39': 24, '40': 17, '41': 37, '42': 30, '43': 33, '44': 18, '45': 33, '46': 19, '47': 39, '48': 33, '49': 69, '50': 16, '51': 67, '52': 27, '53': 33, '54': 21, '55': 40, '56': 40, '57': 29, '58': 44, '59': 32, '60': 84, '61': 52, '62': 25, '63': 35, '64': 37, '65': 43, '66': 37, '67': 38, '68': 22, '69': 14, '70': 39, '71': 43, '72': 77, '73': 45, '74': 34, '75': 72, '76': 41, '77': 56, '78': 51, '79': 29, '80': 41, '81': 39, '82': 47, '83': 41, '84': 43, '85': 40, '86': 29, '87': 38, '88': 36, '89': 43, '90': 35, '91': 35, '92': 38, '93': 42, '94': 56, '95': 30, '96': 19, '97': 30, '98': 38, '99': 29, '100': 41, '101': 51, '102': 33, '103': 60, '104': 45, '105': 42, '106': 29, '107': 87, '108': 76, '109': 32, '110': 20, '111': 29, '112': 53, '113': 41, '114': 42, '115': 41, '116': 40, '117': 39, '118': 37, '119': 20, '120': 26, '121': 38, '122': 61, '123': 24, '124': 30, '125': 42, '126': 51, '127': 55, '128': 33, '129': 16, '130': 36, '131': 35, '132': 32, '133': 40, '134': 47, '135': 52, '136': 39, '137': 10, '138': 39, '139': 28, '140': 29, '141': 42, '142': 52, '143': 15, '144': 42, '145': 49, '146': 25, '147': 36, '148': 44, '149': 45, '150': 48, '151': 22, '152': 43, '153': 27, '154': 25, '155': 39, '156': 21, '157': 19, '158': 31, '159': 54, '160': 12, '161': 51, '162': 19, '163': 56, '164': 22, '165': 16, '166': 40, '167': 53, '168': 22, '169': 48, '170': 41, '171': 52, '172': 42, '173': 42, '174': 48, '175': 41, '176': 38, '177': 50, '178': 56, '179': 48, '180': 26, '181': 38, '182': 20, '183': 36, '184': 56, '185': 24, '186': 49, '187': 44, '188': 38, '189': 34, '190': 8, '191': 38, '192': 27, '193': 21, '194': 40, '195': 34, '196': 48, '197': 25, '198': 30, '199': 42, '200': 19, '201': 34, '202': 51, '203': 35, '204': 12, '205': 58, '206': 29, '207': 49, '208': 22, '209': 33, '210': 26, '211': 27, '212': 27, '213': 35, '214': 34, '215': 41, '216': 38, '217': 44, '218': 42, '219': 37, '220': 32, '221': 30, '222': 34, '223': 37, '224': 24, '225': 39, '226': 43, '227': 37, '228': 35, '229': 33, '230': 27, '231': 37, '232': 40, '233': 24, '234': 17, '235': 41, '236': 25, '237': 31, '238': 29, '239': 36, '240': 5, '241': 25, '242': 20, '243': 52, '244': 24, '245': 40, '246': 19, '247': 31, '248': 30, '249': 54, '250': 30, '251': 35, '252': 28, '253': 23, '254': 20, '255': 28, '256': 41, '257': 22, '258': 45, '259': 44, '260': 14, '261': 35, '262': 40, '263': 44, '264': 38, '265': 45, '266': 44, '267': 31, '268': 41, '269': 37, '270': 17, '271': 43, '272': 45, '273': 29, '274': 20, '275': 37, '276': 38, '277': 39, '278': 22, '279': 32, '280': 42, '281': 56, '282': 21, '283': 20, '284': 22, '285': 54, '286': 31, '287': 68, '288': 39, '289': 6, '290': 30, '291': 32, '292': 46, '293': 57, '294': 27, '295': 17, '296': 38, '297': 24, '298': 50, '299': 44, '300': 24, '301': 41, '302': 50, '303': 57, '304': 15, '305': 46, '306': 24, '307': 13, '308': 4, '309': 20, '310': 20, '311': 21, '312': 33, '313': 34, '314': 27, '315': 9, '316': 32, '317': 34, '318': 31, '319': 8, '320': 31, '321': 38, '322': 10, '323': 34, '324': 14, '325': 2, '326': 38, '327': 10})
In [6]:
degree = dict(nx.degree(G)) # Create a dictionary so that the node's attributes doesn't take in the entire list of degree values
In [7]:
nx.set_node_attributes(G, degree, 'degree')
In [8]:
k = sum(degree.values())/ len(degree) # Calculate the average degree
print("Average degree:", k)
Average degree: 35.584097859327215
In [9]:
def r_zero(p,k):
    return p*k
In [10]:
r_zero(p,k)
Out[10]:
22.24006116207951

Based on this network's average number of contacts per person, also known as degree, the value of $k$ is 35.584097859327215. I calculated this by dividing the sum of all the node’s degree value by the total number of nodes. Based on this network's average number of contacts per person, the value $R_{0}$ is 22.24006116207951. I determined this value by multiplying the probability of a node being infected (0.625) by the average degree value (35.584097859327215). Based on these values, it is very likely that the entire network will be infected.

2. Creating an SIR simulation based on the network's p and k values, using a similar strategy for creating a cascade¶

In [11]:
import copy as copy
In [12]:
import random as random
In [13]:
nx.set_node_attributes(G,"susceptible","status")
names = list(G.nodes)
nx.set_node_attributes(G, dict(zip(G.nodes, names)), "names")
In [14]:
initial_infected_nodes = []
for x in range(0,5):
    initial_infected_nodes.append(random.choice(names))
for i in initial_infected_nodes:
    G.nodes[i]["status"] = "infected"
In [15]:
pos = nx.spring_layout(G)
In [16]:
alt.data_transformers.disable_max_rows()
viz_1 = nxa.draw_networkx(G, 
                        pos=pos,
                        node_color="status",
                        node_tooltip = "names",
                        cmap='category10'
                       )
viz_1.interactive()
C:\Users\ericg\anaconda3\Lib\site-packages\altair\utils\core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
C:\Users\ericg\anaconda3\Lib\site-packages\altair\utils\core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
Out[16]:
In [17]:
def sir_sim(G):
    new_infected_nodes = []
    num_infected = 0
    for n,d in G.nodes.data():
        if d["status"] == "infected":
            for i in G.neighbors(n):
                if (choices(['infect','nothing'],weights=[p,1-p],k=1)[0]) == 'infect':
                    new_infected_nodes.append(i) # append the newly infected node
                    num_infected += 1
            d["status"]="recovered" # immediately recover from the virus
        # check to see if 
        for m in range(0,num_infected):
            if(n==new_infected_nodes[m]) and d["status"] == "susceptible": # checks to see if the susceptible node is the same as the newly infected node
            # AND if the node is not recovered
                d["status"]="infected"
        
In [18]:
plots = []
for n in range(0,10): #run the simulation 10 times
    sir_sim(G)
    plot = nxa.draw_networkx(G, 
                            pos=pos,
                            node_color="status",
                            node_tooltip = "names",
                            cmap='category10'
                           )
    plots.append(plot)
alt.hconcat(*plots)
C:\Users\ericg\anaconda3\Lib\site-packages\altair\utils\core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
C:\Users\ericg\anaconda3\Lib\site-packages\altair\utils\core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
C:\Users\ericg\anaconda3\Lib\site-packages\altair\utils\core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
C:\Users\ericg\anaconda3\Lib\site-packages\altair\utils\core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
C:\Users\ericg\anaconda3\Lib\site-packages\altair\utils\core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
C:\Users\ericg\anaconda3\Lib\site-packages\altair\utils\core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
C:\Users\ericg\anaconda3\Lib\site-packages\altair\utils\core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
C:\Users\ericg\anaconda3\Lib\site-packages\altair\utils\core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
C:\Users\ericg\anaconda3\Lib\site-packages\altair\utils\core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
C:\Users\ericg\anaconda3\Lib\site-packages\altair\utils\core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
C:\Users\ericg\anaconda3\Lib\site-packages\altair\utils\core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
C:\Users\ericg\anaconda3\Lib\site-packages\altair\utils\core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
C:\Users\ericg\anaconda3\Lib\site-packages\altair\utils\core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
C:\Users\ericg\anaconda3\Lib\site-packages\altair\utils\core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
C:\Users\ericg\anaconda3\Lib\site-packages\altair\utils\core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
C:\Users\ericg\anaconda3\Lib\site-packages\altair\utils\core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
C:\Users\ericg\anaconda3\Lib\site-packages\altair\utils\core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
C:\Users\ericg\anaconda3\Lib\site-packages\altair\utils\core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
C:\Users\ericg\anaconda3\Lib\site-packages\altair\utils\core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
C:\Users\ericg\anaconda3\Lib\site-packages\altair\utils\core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
Out[18]:
In [19]:
nx.set_node_attributes(G,"susceptible","status")
names = list(G.nodes)
nx.set_node_attributes(G, dict(zip(G.nodes, names)), "names")
In [20]:
initial_infected_nodes = []
for x in range(0,5):
    initial_infected_nodes.append(random.choice(names))
for i in initial_infected_nodes:
    G.nodes[i]["status"] = "infected"
In [21]:
statuses = nx.get_node_attributes(G, "status")
status_df = pd.DataFrame({"Step 0": statuses})
In [22]:
for i in range(10): # Rerun the simulation 10 times
    sir_sim(G)
    new_statuses = nx.get_node_attributes(G,'status')
    status_df["Step " + str(i+1)] = list(new_statuses.values()) # Adds a column to the dataframe
In [23]:
status_df
Out[23]:
Step 0 Step 1 Step 2 Step 3 Step 4 Step 5 Step 6 Step 7 Step 8 Step 9 Step 10
1 susceptible susceptible susceptible susceptible susceptible susceptible susceptible susceptible susceptible susceptible susceptible
10 susceptible susceptible susceptible susceptible susceptible susceptible susceptible susceptible susceptible susceptible susceptible
100 susceptible susceptible susceptible susceptible susceptible susceptible susceptible susceptible susceptible susceptible susceptible
101 susceptible susceptible susceptible susceptible susceptible susceptible susceptible susceptible susceptible susceptible susceptible
102 susceptible susceptible susceptible susceptible susceptible susceptible susceptible susceptible susceptible susceptible susceptible
... ... ... ... ... ... ... ... ... ... ... ...
95 susceptible infected recovered recovered recovered recovered recovered recovered recovered recovered recovered
96 susceptible susceptible susceptible susceptible susceptible susceptible infected recovered recovered recovered recovered
97 susceptible susceptible susceptible susceptible susceptible susceptible susceptible susceptible susceptible susceptible susceptible
98 susceptible infected recovered recovered recovered recovered recovered recovered recovered recovered recovered
99 susceptible susceptible susceptible susceptible susceptible susceptible susceptible susceptible susceptible susceptible susceptible

327 rows × 11 columns

Based on the data, the infection will stop over time. After each time step, an infected node will recover by the beginning of the next time step and will be unable to infect another node. If this pattern continues, most of the nodes will eventually recover, being unable to reinfect another node, thus ending the infection cycle.

3. Creating a Static Percolation and seeing if it matches with the dynamic visualizations¶

In [51]:
def percolation(G, p, seed=None):
    random.seed(seed)
    percolated_edges = []

    for u,v in G.edges():
        if random.choices(['open','blocked'],weights=[p,1-p],k=1)[0] == 'open':
            percolated_edges.append((u,v))

    return percolated_edges
In [52]:
percolated_edges = percolation(G,p,seed=42)
In [53]:
nx.set_edge_attributes(G, {edge:"open" if edge in percolated_edges else "blocked" for edge in G.edges()}, name="percolation") 
In [54]:
pos2 = nx.spring_layout(G, seed=42)
In [63]:
perc_chart = nxa.draw_networkx(G,
                        pos=pos2,
                        edge_color = "percolation",
                        alpha = 0.6,
                        node_color="red",
                        edge_tooltip=["percolation"]
                        )
perc_chart = perc_chart.properties(width=1080,height=720, title="Static Percolation")
perc_chart                   
C:\Users\ericg\anaconda3\Lib\site-packages\altair\utils\core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
C:\Users\ericg\anaconda3\Lib\site-packages\altair\utils\core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
Out[63]:

Based on the static percolation of the SIR epidemic model, I can confirm, that just as the temporal model showed ⅝ of the nodes becoming infected and ⅜ of the nodes being blocked from infection, ⅝ of the edges in the static model are orange (open to infection) and ⅜ of the edges are blue (blocked from infection). The data is exactly the same in both visualizations in different ways. I learned that both visualizations are good representations of the data.

4. Expanding the previous simulation in Part 2 to be a SIRS simulation¶

In [28]:
nx.set_node_attributes(G, 2, "time_steps")
In [42]:
def sirs_sim(G):
    new_infected_nodes = []
    num_infected = 0
    for n,d in G.nodes.data():
        if d["status"] == "infected":
            for i in G.neighbors(n):
                if (choices(['infect','nothing'],weights=[p,1-p],k=1)[0]) == 'infect':
                    new_infected_nodes.append(i) # append the newly infected node
                    num_infected += 1
            d["status"]="recovered" # immediately recover from the virus
        # check to see if the nodes have been infected
        for m in range(0,num_infected):
            if(n==new_infected_nodes[m]) and d["status"] == "susceptible": # checks to see if the susceptible node is the same as the newly infected node
            # AND if the node is not recovered
                d["status"]="infected"
        if(d["time_steps"])<1 and d["status"] == "recovered": # checks to see if the node is recovered and has had its immunity worn off
            d["time_steps"]=2 # resets the time steps
            d["status"]="susceptible" # Removes the node's immunity
        else:
            d["time_steps"] -= 1 # Decreases the number of cycles that a node is immune for by 1
In [43]:
nx.set_node_attributes(G, 2, "time_steps")
In [44]:
nx.set_node_attributes(G,"susceptible","status")
names = list(G.nodes)
nx.set_node_attributes(G, dict(zip(G.nodes, names)), "names")
In [45]:
initial_infected_nodes = []
for x in range(0,5):
    initial_infected_nodes.append(random.choice(names))
for i in initial_infected_nodes:
    G.nodes[i]["status"] = "infected"
In [34]:
sirs_sim(G)
In [46]:
plots = []
for n in range(0,10): #run the simulation 10 times
    sirs_sim(G)
    plot = nxa.draw_networkx(G, 
                            pos=pos,
                            node_color="status",
                            node_tooltip = "names",
                            cmap='category10'
                           )
    plots.append(plot)
alt.hconcat(*plots)
C:\Users\ericg\anaconda3\Lib\site-packages\altair\utils\core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
C:\Users\ericg\anaconda3\Lib\site-packages\altair\utils\core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
C:\Users\ericg\anaconda3\Lib\site-packages\altair\utils\core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
C:\Users\ericg\anaconda3\Lib\site-packages\altair\utils\core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
C:\Users\ericg\anaconda3\Lib\site-packages\altair\utils\core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
C:\Users\ericg\anaconda3\Lib\site-packages\altair\utils\core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
C:\Users\ericg\anaconda3\Lib\site-packages\altair\utils\core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
C:\Users\ericg\anaconda3\Lib\site-packages\altair\utils\core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
C:\Users\ericg\anaconda3\Lib\site-packages\altair\utils\core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
C:\Users\ericg\anaconda3\Lib\site-packages\altair\utils\core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
C:\Users\ericg\anaconda3\Lib\site-packages\altair\utils\core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
C:\Users\ericg\anaconda3\Lib\site-packages\altair\utils\core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
C:\Users\ericg\anaconda3\Lib\site-packages\altair\utils\core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
C:\Users\ericg\anaconda3\Lib\site-packages\altair\utils\core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
C:\Users\ericg\anaconda3\Lib\site-packages\altair\utils\core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
C:\Users\ericg\anaconda3\Lib\site-packages\altair\utils\core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
C:\Users\ericg\anaconda3\Lib\site-packages\altair\utils\core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
C:\Users\ericg\anaconda3\Lib\site-packages\altair\utils\core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
C:\Users\ericg\anaconda3\Lib\site-packages\altair\utils\core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
C:\Users\ericg\anaconda3\Lib\site-packages\altair\utils\core.py:395: FutureWarning: the convert_dtype parameter is deprecated and will be removed in a future version.  Do ``ser.astype(object).apply()`` instead if you want ``convert_dtype=False``.
  col = df[col_name].apply(to_list_if_array, convert_dtype=False)
Out[46]:
In [36]:
nx.set_node_attributes(G, 2, "time_steps")
In [37]:
nx.set_node_attributes(G,"susceptible","status")
names = list(G.nodes)
nx.set_node_attributes(G, dict(zip(G.nodes, names)), "names")
In [38]:
initial_infected_nodes = []
for x in range(0,5):
    initial_infected_nodes.append(random.choice(names))
for i in initial_infected_nodes:
    G.nodes[i]["status"] = "infected"
In [39]:
statuses = nx.get_node_attributes(G, "status")
status_df = pd.DataFrame({"Step 0": statuses})
In [40]:
for i in range(10): # Rerun the simulation 10 times
    sirs_sim(G)
    new_statuses = nx.get_node_attributes(G,'status')
    status_df["Step " + str(i+1)] = list(new_statuses.values()) # Adds a column to the dataframe
In [41]:
status_df
Out[41]:
Step 0 Step 1 Step 2 Step 3 Step 4 Step 5 Step 6 Step 7 Step 8 Step 9 Step 10
1 susceptible susceptible susceptible susceptible susceptible susceptible susceptible susceptible susceptible susceptible susceptible
10 susceptible susceptible susceptible susceptible susceptible susceptible susceptible susceptible susceptible susceptible susceptible
100 susceptible susceptible susceptible susceptible susceptible susceptible susceptible susceptible susceptible susceptible susceptible
101 susceptible susceptible susceptible susceptible susceptible susceptible susceptible susceptible susceptible susceptible susceptible
102 susceptible susceptible susceptible susceptible susceptible susceptible susceptible susceptible susceptible susceptible susceptible
... ... ... ... ... ... ... ... ... ... ... ...
95 susceptible infected recovered recovered susceptible susceptible infected recovered susceptible infected recovered
96 susceptible susceptible susceptible infected susceptible susceptible susceptible susceptible infected susceptible infected
97 susceptible susceptible susceptible susceptible susceptible susceptible susceptible susceptible susceptible susceptible susceptible
98 susceptible infected recovered recovered susceptible susceptible infected recovered susceptible infected recovered
99 susceptible susceptible susceptible infected susceptible susceptible susceptible susceptible susceptible susceptible susceptible

327 rows × 11 columns

By extending the initial epidemic simulation for the SIRS mode, the speed of infection will increase over time. This is because every recovered node will become susceptible to reinfection after only 2 time steps. In terms of the extent of the epidemic, the entire network will become more likely to be reinfected multiple times as long as the infection exists.